package jacksen.cluster;

import android.content.Context;
import android.graphics.Point;
import android.os.Handler;
import android.os.Message;

import com.amap.api.maps.AMap;
import com.amap.api.maps.Projection;
import com.amap.api.maps.model.CameraPosition;
import com.amap.api.maps.model.LatLng;
import com.amap.api.maps.model.Marker;

import java.util.ArrayList;
import java.util.List;

/**
 * Created by jacksen on 2015/12/4.
 */
public class ClusterOverlay implements AMap.OnCameraChangeListener {

    private static int clusterRange = 200;

    private Context context;
    private AMap aMap;
    private List<ClusterInter> clusterInters;
    private List<MarkersCluster> markersClusters;
    private Projection projection;

    /**
     * @param context
     * @param aMap
     */
    public ClusterOverlay(Context context, AMap aMap) {
        this(context, aMap, null);
    }

    /**
     * @param context
     * @param aMap
     * @param clusterRange
     */
    public ClusterOverlay(Context context, AMap aMap, int clusterRange) {
        this(context, aMap, null, clusterRange);
    }

    /**
     * @param context
     * @param aMap
     * @param clusterInters
     */
    public ClusterOverlay(Context context, AMap aMap, List<ClusterInter> clusterInters) {
        this(context, aMap, clusterInters, clusterRange);
    }

    /**
     * @param context
     * @param aMap
     * @param clusterInters
     * @param clusterRange
     */
    public ClusterOverlay(Context context, AMap aMap, List<ClusterInter> clusterInters, int clusterRange) {
        this.context = context;
        this.aMap = aMap;
        if (null != clusterInters) {
            this.clusterInters = clusterInters;
        } else {
            this.clusterInters = new ArrayList<>();
        }
        this.clusterRange = clusterRange;
        //
        markersClusters = new ArrayList<>();
        this.aMap.setOnCameraChangeListener(this);
        projection = aMap.getProjection();

    }

    /**
     *
     */
    private void resetClusters() {
        new Runnable() {
            @Override
            public void run() {
                for (ClusterInter clusterInter : clusterInters) {
                    LatLng latLng = clusterInter.getPosition();
                    Point point = projection.toScreenLocation(latLng);
                    //
                    MarkersCluster markersCluster = getCluster(point);
                    if (null != markersCluster) {
                        markersCluster.addClusterItem(clusterInter);
                    } else {
                        markersCluster = new MarkersCluster(point, latLng);
                        markersCluster.addClusterItem(clusterInter);
                        markersClusters.add(markersCluster);
                    }
                }
                handler.sendEmptyMessage(0);
            }
        };
    }

    /**
     *
     * @param clusterInter
     */
    private void assignSingleCluster(ClusterInter clusterInter) {
        LatLng latLng = clusterInter.getPosition();
        Point point = projection.toScreenLocation(latLng);
        MarkersCluster markersCluster = getCluster(point);
        if (null != markersCluster) {
            markersCluster.addClusterItem(clusterInter);
            updateCluster(markersCluster);
        } else {
            markersCluster = new MarkersCluster(point, latLng);
            markersCluster.addClusterItem(clusterInter);
            markersClusters.add(markersCluster);
            //
            Marker marker = aMap.addMarker(markersCluster.getMarkerOptions(context));
            markersCluster.setMarker(marker);
        }
    }

    /**
     *
     * @param markersCluster
     */
    private void updateCluster(MarkersCluster markersCluster){
        markersCluster.getMarker().setIcon(markersCluster.getBitmapDescriptor(context, markersCluster.getClusterInters().size()));
    }


    /**
     * @return
     */
    private MarkersCluster getCluster(Point point) {
        for (MarkersCluster cluster : markersClusters) {
            Point po = cluster.getCenterPoint();
            double distance = ClusterUtil.getDistanceBetweenTwoPoints(point.x, point.y, po.x
                    , po.y);
            if (distance < clusterRange) {
                return cluster;
            }
        }
        return null;
    }

    /**
     * 添加一个聚合点
     * @param clusterInter
     */
    public void addClusterItem(ClusterInter clusterInter) {
        clusterInters.add(clusterInter);
        assignSingleCluster(clusterInter);
    }

    @Override
    public void onCameraChange(CameraPosition cameraPosition) {

    }

    @Override
    public void onCameraChangeFinish(CameraPosition cameraPosition) {

    }

    /**
     *
     */
    private Handler handler = new Handler() {
        public void handleMessage(Message message) {
            addClusterToMap();
        }
    };

    /**
     * 添加聚合点到地图上
     */
    private void addClusterToMap() {
        aMap.clear();
        for (MarkersCluster cluster : markersClusters) {
            Marker marker = aMap.addMarker(cluster.getMarkerOptions(context));
            cluster.setMarker(marker);
        }
    }

}
